package midend.IR_Optimizer;

import midend.IR_Instruction.*;
import midend.IR_Type.*;
import midend.IR_Value.*;
import midend.IR_Module;

import java.util.*;

public class GlobalArr_To_LocalArr  {
    /*
    * 优化全零初始化，且仅被main函数引用的全局变量数组，将其变为局部数组变量*/
    //全局数组局部化（仅针对main函数）
    private final HashSet<String> varsToRemove = new HashSet<>();

    public void Optimize(IR_Module module) {
        int length = 0;
        ArrayList<IR_FuncBlock> funcs = module.getFuncBlocks();
        HashMap<String, IR_Value> globalVars = module.get_Gloabal_Varmap();
        // 找到main函数
        IR_FuncBlock main_function = null;
        for (IR_FuncBlock function : funcs) {
            if (function.get_FuncName().equals("main")) {
                main_function = function;
                break;
            }
        }
        if (main_function != null) {
            for (String globalVar : globalVars.keySet()) {
                    if (globalVars.get(globalVar) instanceof IR_Array_Value arr) {  // 如果全局变量是数组
                        if (arr.get_is_AllZero() && isOnlyUsedInMain(globalVar, funcs)) {
                            length += arr.getSize();
                            transform_Global_To_Local(globalVars, globalVar, main_function, funcs);
                        }
                    }
                if (length > 500000) {
                    break;
                }
            }
            // 删除原本的全局变量
            for (String globalVar : varsToRemove) {
                globalVars.remove(globalVar);
            }
        }
    }

//    private boolean isArrayType(IRGlobalRegRef globalVar) {
//        IRPointerType pointerType = (IRPointerType) globalVar.getType();
//        return pointerType.getBaseType() instanceof IRArrayType;
//    }

    private boolean isOnlyUsedInMain(String globalVar, ArrayList<IR_FuncBlock> funcs) {
        for (IR_FuncBlock function : funcs) {
            if (function.get_FuncName().equals("main")) {
                for (IR_BaseBlock bb : function.get_bb_List()) {
                    for (Instruction instruction : bb.get_Instruction_List()) {
                        //main函数中仅看call指令
                        if (instruction instanceof Call_Instruction call_Instruction) {
                            for (IR_Value param : call_Instruction.get_params()) {
                                if (param instanceof IR_VirtualReg_Value pa) {
                                    if (pa.getIdentity().equals(globalVar)){
                                        return false;
                                    }
                                }
                            }
                        }
                    }
                }
            } else {
                for (IR_BaseBlock bb : function.get_bb_List()) {
                    for (Instruction instruction : bb.get_Instruction_List()) {
                        for (IR_Value op : instruction.get_op()) {
                            if (op == null) {
                                continue;
                            }
                            if (op.get_ValueName().equals(globalVar)) {
                                return false;
                            }
                        }
                    }
                }
            }
        }
        return true;
    }

    private void transform_Global_To_Local(HashMap<String, IR_Value> globalVars, String globalVar, IR_FuncBlock
            mainfunction, ArrayList<IR_FuncBlock> funcs) {
        IR_Pointer pointerType = new IR_Pointer(globalVars.get(globalVar).get_Type());
        // 在main函数开始位置声明数组
        IR_Value res_Register;
        res_Register = new IR_VirtualReg_Value("arr", pointerType);
        Instruction alloc_Inst = new Alloc_Instrction(Collections.singletonList(res_Register),mainfunction.get_bb_List().get(0));
        mainfunction.get_bb_List().get(0).add_InstructionList(alloc_Inst);
        //替换所有对globalVar的使用
        for (IR_FuncBlock functionBlock : funcs) {
            for (IR_BaseBlock bb : functionBlock.get_bb_List()) {
                for (Instruction instruction : bb.get_Instruction_List()) {
                    for (int i = 0; i < instruction.get_op().size(); i++) {
                        if (instruction.get_op().get(i) == null) {
                            continue;
                        }
                        if (instruction.get_op().get(i).get_ValueName().equals(globalVar)) {
                            instruction.set_Op(i, res_Register);
                            if (instruction instanceof Pointer_Instruction) {
                                ((Pointer_Instruction) instruction).set_Base(res_Register);
                            }
                        }
                    }
                }
            }
        }
        // 标记需要移除的全局变量
        varsToRemove.add(globalVar);
    }
}